package web.stu.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import web.stu.common.ErrorCode;
import web.stu.exception.BusinessException;
import web.stu.mapper.ClassMapper;
import web.stu.mapper.CourseMapper;
import web.stu.mapper.ScoreMapper;
import web.stu.model.dto.score.AddScoreDTO;
import web.stu.model.dto.score.QueryScoreDTO;
import web.stu.model.dto.score.UpdateScoreDTO;
import web.stu.model.entity.Class;
import web.stu.model.entity.Course;
import web.stu.model.entity.Score;
import web.stu.model.entity.User;
import web.stu.model.enums.ScoreAuditEnum;
import web.stu.model.enums.UserRoleEnum;
import web.stu.model.vo.ScoreVO;
import web.stu.service.ClassService;
import web.stu.service.CourseService;
import web.stu.service.ScoreService;
import web.stu.service.UserService;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author administer
 * @description 针对表【score(成绩表)】的数据库操作Service实现
 * @createDate 2025-05-13 19:55:16
 */
@Slf4j
@Service
public class ScoreServiceImpl extends ServiceImpl<ScoreMapper, Score> implements ScoreService {

    @Resource
    // 为了解决CourseServiceImpl里调用ScoreService的循环依赖问题
    @Lazy
    private CourseService courseService;

    @Resource
    private ClassService classService;

    @Resource
    private UserService userService;

    @Resource
    private ClassMapper classMapper;

    @Resource
    private CourseMapper courseMapper;

    @Override
    public Page<ScoreVO> listAllScoresToStudent(QueryScoreDTO queryScoreDTO, HttpServletRequest request) {
        // 非空判断
        if (ObjUtil.isEmpty(queryScoreDTO)) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        // 分页
        long current = queryScoreDTO.getCurrent();
        long pageSize = queryScoreDTO.getPageSize();
        Page<Score> scorePage = new Page<>(current, pageSize);

        // 只能搜索当前学生id的课程
        if (!Objects.equals(queryScoreDTO.getStudentId(), userService.getLoginUser(request).getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "只能获取自己的成绩");
        }

        // 根据课程名称查询
        String courseName = queryScoreDTO.getCourseName();
        if (StrUtil.isNotBlank(courseName)) {
            // 根据课程名称获取课程id
            Course course = courseService.getOne(new QueryWrapper<Course>().select("id").like("course_name", courseName));
            if (ObjUtil.isEmpty(course)) {
                throw new BusinessException(ErrorCode.NOT_FOUND, "没有该课程");
            }
            // 设置课程id根据课程id进行查询
            queryScoreDTO.setCourseId(course.getId());
        }

        QueryWrapper<Score> queryWrapper = this.getQueryWrapper(queryScoreDTO);
        Page<Score> scores = this.page(scorePage, queryWrapper);
        List<ScoreVO> scoreVOS = convertToVOList(scores.getRecords());
        Page<ScoreVO> scoreVOPage = new Page<>(current, pageSize, scores.getTotal());
        scoreVOPage.setRecords(scoreVOS);
        return scoreVOPage;
    }

    @Override
    public Page<ScoreVO> listScoresToTeacher(QueryScoreDTO queryScoreDTO, HttpServletRequest request) {
        // 非空判断
        if (ObjUtil.isEmpty(queryScoreDTO)) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        // 分页
        long current = queryScoreDTO.getCurrent();
        long pageSize = queryScoreDTO.getPageSize();
        Page<Score> scorePage = new Page<>(current, pageSize);

        // 根据课程名称查询
        String courseName = queryScoreDTO.getCourseName();
        if (StrUtil.isNotBlank(courseName)) {
            List<Course> courseList = courseService.list(new QueryWrapper<Course>().select("id").like("course_name", courseName));

            // 设置课程id根据课程id进行查询
            queryScoreDTO.setQueryCourseIds(courseList.stream().map(Course::getId).collect(Collectors.toList()));
        }

        //根据班级名称查询
        String className = queryScoreDTO.getClassName();
        if (StrUtil.isNotBlank(className)) {
            // 根据班级名称获取班级id
            List<Class> classList = classService.list(new QueryWrapper<Class>().select("id").like("class_name", className));

            // 设置班级id根据班级id进行查询
            queryScoreDTO.setQueryClassIds(classList.stream().map(Class::getId).collect(Collectors.toList()));
        }

        QueryWrapper<Score> queryWrapper = this.getQueryWrapper(queryScoreDTO);
        Page<Score> scores = this.page(scorePage, queryWrapper);
        List<ScoreVO> scoreVOS = convertToVOList(scores.getRecords());
        Page<ScoreVO> scoreVOPage = new Page<>(current, pageSize, scores.getTotal());
        scoreVOPage.setRecords(scoreVOS);
        return scoreVOPage;
    }


    @Override
    public Integer addScore(AddScoreDTO addScoreDTO, HttpServletRequest request) {
        // 非空校验
        if (ObjUtil.isEmpty(addScoreDTO)) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        //  校验教师身份 controller 已做校验
        Integer studentId = addScoreDTO.getStudentId();
        Integer courseId = addScoreDTO.getCourseId();
        Integer teacherId = addScoreDTO.getTeacherId();
        Integer classId = addScoreDTO.getClassId();

        // 1. 校验学生、课程、教师是否存在
        validateRelations(studentId, courseId, teacherId, classId, addScoreDTO.getScore());

        // 校验是否有该课程成绩记录
        LambdaQueryWrapper<Score> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Score::getStudentId, studentId)
                .eq(Score::getCourseId, courseId);
        if (this.count(wrapper) > 0) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR, "该学生在此课程中已有成绩记录");
        }

        // 创建新成绩记录
        Score score = new Score();
        BeanUtil.copyProperties(addScoreDTO, score);

        // 查看分数是否符合标准
        if (score.getScore().compareTo(BigDecimal.valueOf(99)) > 0 || score.getScore().compareTo(BigDecimal.valueOf(59)) < 0) {
            // 分数出现异常
            // 设置分数的状态 设置为异常
            score.setStatus(ScoreAuditEnum.EXCEPTION.getValue());
        }

        // 保存
        if (!this.save(score)) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "添加成绩失败");
        }

        return score.getId();
    }

    @Override
    public Integer updateScore(UpdateScoreDTO updateScoreDTO, HttpServletRequest request) {
        // 非空判断
        if (ObjUtil.isEmpty(updateScoreDTO) || updateScoreDTO.getId() == null) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        //  校验身份 controller 已做校验
        // 获取数据库中数据
        Score oldScore = this.getById(updateScoreDTO.getId());
        if (oldScore == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND, "成绩不存在");
        }
        // 校验学生、课程、教师是否存在
        validateRelations(updateScoreDTO.getStudentId(), updateScoreDTO.getCourseId(), updateScoreDTO.getTeacherId(), updateScoreDTO.getClassId(), updateScoreDTO.getScore());

        // 如果为教师修改 修改异常的成绩会自动变成审核中状态
        User loginUser = userService.getLoginUser(request);
        if (userService.isCompareRole(loginUser, UserRoleEnum.TEACHER.getKey())) {
            // 如果状态为异常 修改自动修改为审核中
            if (Objects.equals(oldScore.getStatus(), ScoreAuditEnum.EXCEPTION.getValue())) {
                updateScoreDTO.setStatus(ScoreAuditEnum.REVIEWING.getValue());
            }
        }


        // 进行修改
        Score score = new Score();
        BeanUtil.copyProperties(updateScoreDTO, score);
        if (!this.updateById(score)) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "更新成绩失败");
        }
        return score.getId();
    }

    @Override
    public void deleteScore(Integer id) {
        Score score = this.getById(id);
        if (score == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND, "成绩不存在");
        }
        // 判断成绩是否异常/审核中，异常成绩不能删除
        if (!Objects.equals(score.getStatus(), ScoreAuditEnum.NORMAL.getValue())) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR, "异常成绩不能删除");
        }

        if (!this.removeById(id)) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除成绩失败");
        }
    }

    @Override
    public ScoreVO getScoreById(Integer id) {
        Score score = this.getById(id);
        if (score == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND, "成绩不存在");
        }
        return convertToVO(score);
    }

    @Override
    public List<ScoreVO> getScoresByStudent(Integer studentId) {
        LambdaQueryWrapper<Score> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Score::getStudentId, studentId);
        List<Score> scores = this.list(wrapper);
        return convertToVOList(scores);
    }

    @Override
    public List<ScoreVO> getScoresByCourse(Integer courseId) {
        LambdaQueryWrapper<Score> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Score::getCourseId, courseId);
        List<Score> scores = this.list(wrapper);
        return convertToVOList(scores);
    }

    @Override
    public void updateScoreByAdminAudit(UpdateScoreDTO updateScoreDTO, HttpServletRequest request) {
        // 非空判断
        if (ObjUtil.isEmpty(updateScoreDTO) || updateScoreDTO.getId() == null) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        // 查询数据库是否存在
        Score oldScore = this.getById(updateScoreDTO.getId());
        // 判断状态是否相等
        if (Objects.equals(oldScore.getStatus(), updateScoreDTO.getStatus())) {
            return;
        }
        // 如果需要标记异常，但是状态为审核中

        // 修改状态
        Score score = new Score();
        score.setId(updateScoreDTO.getId());
        score.setStatus(updateScoreDTO.getStatus());
        boolean res = this.updateById(score);
        if (!res) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "更新失败");
        }
    }

    // 私有方法：转换Score到ScoreVO
    private ScoreVO convertToVO(Score score) {
        ScoreVO vo = ScoreVO.objToVO(score);
        // 填充关联信息
        vo.setStudentName(userService.getById(score.getStudentId()).getRealName());
        vo.setCourseName(courseService.getById(score.getCourseId()).getCourseName());
        vo.setTeacherName(userService.getById(score.getTeacherId()).getRealName());
        vo.setClassName(classService.getById(score.getClassId()).getClassName());
        return vo;
    }

    // 私有方法：批量转换
    private List<ScoreVO> convertToVOList(List<Score> scores) {
        return scores.stream().map(this::convertToVO).collect(Collectors.toList());
    }

    // 私有方法：校验关联关系
    private void validateRelations(Integer studentId, Integer courseId, Integer teacherId, Integer classId, BigDecimal score) {
        User student = userService.getById(studentId);
        if (student == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND, "学生不存在");
        }
        Course course = courseService.getById(courseId);
        if (course == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND, "课程不存在");
        }
        User teacher = userService.getById(teacherId);
        if (teacher == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND, "教师不存在");
        }

        //  校验学生与班级是否冲突
        Integer countByStudentClassId = classMapper.getCountByStudentClassId(Collections.singletonList(studentId), classId);
        if (countByStudentClassId <= 0) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR, "学生不在该班级内");
        }
        //  教师是否为该班级、该课程授课
        Integer countByTeacherClassCourseId = courseMapper.getCountByTeacherClassCourseId(teacherId, classId, courseId);
        if (countByTeacherClassCourseId <= 0) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR, "教师未为该班级该课程授课");
        }
        // 校验是否学生是否选择了这门课
        Integer countByStudentCourseId = courseMapper.getCountByStudentCourseId(studentId, courseId);
        if (countByStudentCourseId <= 0) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR, "学生未选择该课程");
        }

        // 分数参数校验
        if (score.compareTo(BigDecimal.ZERO) <= 0 || score.compareTo(BigDecimal.valueOf(200)) > 0) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR, "分数格式错误");
        }
    }


    private QueryWrapper<Score> getQueryWrapper(QueryScoreDTO queryScoreDTO) {
        // 非空判断
        if (ObjUtil.isEmpty(queryScoreDTO)) {
            throw new BusinessException(ErrorCode.PRIMARY_ERROR);
        }
        // 提取全部元素
        Integer id = queryScoreDTO.getId();
        Integer studentId = queryScoreDTO.getStudentId();
        Integer courseId = queryScoreDTO.getCourseId();
        Integer teacherId = queryScoreDTO.getTeacherId();
        Integer classId = queryScoreDTO.getClassId();
        Integer status = queryScoreDTO.getStatus();
        List<Integer> queryClassIds = queryScoreDTO.getQueryClassIds();
        List<Integer> queryCourseIds = queryScoreDTO.getQueryCourseIds();


        QueryWrapper<Score> scoreQueryWrapper = new QueryWrapper<>();
        scoreQueryWrapper.eq(id != null, "id", id);
        scoreQueryWrapper.eq(studentId != null, "student_id", studentId);
        scoreQueryWrapper.eq(courseId != null, "course_id", courseId);
        scoreQueryWrapper.eq(teacherId != null, "teacher_id", teacherId);
        scoreQueryWrapper.eq(classId != null, "class_id", classId);
        scoreQueryWrapper.eq(status != null, "status", status);
        scoreQueryWrapper.in(CollUtil.isNotEmpty(queryClassIds), "class_id", queryClassIds);
        scoreQueryWrapper.in(CollUtil.isNotEmpty(queryCourseIds), "course_id", queryCourseIds);


        return scoreQueryWrapper;
    }

}




